﻿using System;
using System.Data.Objects;
using System.Linq;
using System.Web.Mvc;
using System.Web.Routing;
using Domain.Abstract;
using Domain.Concrete;
using Domain.Entity;
using Pro260Website.Models;
using Pro260Website.Infrastructure.Filters;
using System.Web;
using System.IO;

namespace Pro260Website.Controllers
{
    public class ReviewController : Controller
    {
        private const int PAGE_SIZE = 10;

        private readonly IReviewRepository _reviewRepository;
        private readonly IFeedbackRepository _feedbackRepository;
        private readonly IAccountRepository _accountRepository;
        private readonly IGameRepository _gameRepository;

        public ReviewController(IReviewRepository reviewRepository, IFeedbackRepository feedbackRepository, IAccountRepository accountRepository,
            IGameRepository gameRepository)
        {
            EFDbContext mainContext = EFDbContext.Instance;
            _reviewRepository = reviewRepository;
            _reviewRepository.Context = mainContext;
            _feedbackRepository = feedbackRepository;
            _feedbackRepository.Context = mainContext;
            _accountRepository = accountRepository;
            _accountRepository.Context = mainContext;
            _gameRepository = gameRepository;
            _gameRepository.Context = mainContext;
        }

        public ViewResult ReviewList(int page = 1)
        {
            var items = _reviewRepository.Reviews;
            var viewModel = new ListingViewModel<Review>()
            {
                Items = items.OrderBy( r => r.PostedDate )
                                .Skip((page-1)*PAGE_SIZE)
                                .Take(PAGE_SIZE),

                PagingInfo = new PagingInfo
                                        {
                                            CurrentPage = page,
                                            ItemsPerPage = PAGE_SIZE,
                                            TotalItems = items.Count()
                                        }
            };

            return View(viewModel);
        }

        public ViewResult RandomReview()
        {
            Random r = new Random();
            int num = r.Next(_reviewRepository.Reviews.Count() - 1);
            Review review = _reviewRepository.Reviews.OrderBy(g => g.Id).Skip(num).Take(1).SingleOrDefault(g => true);
            return View(review);
        }

        public ViewResult ReviewInfo(int id)
        {
            var review = _reviewRepository.FindReview(id);
            return View(review);
        }

        [HttpGet]
        [Authorize]
        public ViewResult CreateReview(int gameId)
        {
            ViewBag.Title = "Create Review";
            return EditReview(0, gameId);
        }

        [HttpGet]
        [Authorize]
        public ViewResult EditReview(int id, int gameId)
        {
            Review review;
            if (id != 0)
            {
                review = _reviewRepository.FindReview(id);
                ViewBag.Title = "Edit Review";
            }
            else
            {
                review = new Review()
                             {
                                 Account = _accountRepository.FindAccountByUsername(User.Identity.Name),
                                 Game = _gameRepository.FindById(gameId)
                             };
            }

            return View("EditReview", review);
        }

        [HttpPost]
        [YoutubeLinkParse]
        [Authorize]
        public ActionResult EditReview(Review entity, int accountId, int gameId, HttpPostedFileBase video)
        {
            if (video != null)
            {
                var nameOriginal = video.FileName;
                var pathTemp = Path.Combine(Server.MapPath(""), nameOriginal);
                var fileExtension = Path.GetExtension(pathTemp);
         
                var fileName = GenerateID() + fileExtension;
                if (fileExtension.Equals(".swf") || fileExtension.Equals(".wmv"))
                {
                    var path = Path.Combine(Server.MapPath("~/Content/Video"), fileName);
                    entity.FileName = fileName;
                    video.SaveAs(path);
                }
            }

            if (entity.Id == 0)
            {
                entity.Account = _accountRepository.FindAccountByUsername(User.Identity.Name);
                entity.Game = _gameRepository.FindById(gameId);
            }

            entity.PostedDate = DateTime.Now;

            
            if(ModelState.IsValid)
            {
                _reviewRepository.SaveReview(entity);
                //this.UpdateGamePopularValue(entity.Game);
                return RedirectToAction("ReviewList");
            }

            return View(entity);
        }

        [Authorize]
        public ActionResult DeleteReview(int id)
        {
            Review review = _reviewRepository.FindReview(id);

            foreach (Feedback feedback in review.Feedbacks)
            {
                _feedbackRepository.DeleteFeedback(feedback);
                _reviewRepository.SaveReview(review);
            }
            review.Feedbacks = null;

            _reviewRepository.DeleteReview(review);
            return RedirectToAction("ReviewList");
        }

        [HttpGet]
        [Authorize]
        public ActionResult PostFeedback(int reviewId)
        {
            ViewBag.Title = "Leave a Comment";
            return EditFeedback(0, reviewId);
        }

        [HttpGet]
        [Authorize]
        public ActionResult EditFeedback(int feedbackId, int reviewId)
        {
            Feedback feedback;
            int accountId;

            if (feedbackId != 0)
            {
                ViewBag.Title = "Edit Your Feedback";
                feedback = _feedbackRepository.FindFeedback(feedbackId);
                accountId = feedback.Account.Id;

                if (!_reviewRepository.IsFeedbackInReview(reviewId, feedbackId))
                    return RedirectToAction("ReviewList");
            }
            else
            {
                feedback = new Feedback();
                accountId = _accountRepository.FindAccountByUsername(User.Identity.Name).Id;
            }

            var rfInfo = new ReviewFeedbackInfo
                                            {
                                                Feedback = feedback,
                                                ReviewId = reviewId,
                                                AccountId = accountId
                                            };

            return View("EditFeedback", rfInfo);
        }

        [HttpPost]
        [Authorize]
        public ActionResult UpdateFeedback(ReviewFeedbackInfo rfInfo)
        {
            rfInfo.Feedback.PostedDate = DateTime.Now;
            if(rfInfo.Feedback.Message != null)
            {
                rfInfo.Feedback.Account = _accountRepository.FindAccount(rfInfo.AccountId);
                if(rfInfo.Feedback.Id == 0)
                {
                    var review = _reviewRepository.FindReview(rfInfo.ReviewId);
                    review.Feedbacks.Add(rfInfo.Feedback);
                    this.UpdateGamePopularValue(review.Game);

                    _reviewRepository.SaveReview(review);
                }
                else
                    _feedbackRepository.SaveFeedback(rfInfo.Feedback);
            }

            return RedirectToAction("ReviewInfo", new { id = rfInfo.ReviewId});
        }

        [Authorize]
        public ActionResult DeleteFeedback(int reviewId, int feedbackId)
        {
            Feedback feedback = _feedbackRepository.FindFeedback(feedbackId);
            _feedbackRepository.DeleteFeedback(feedback);
            return RedirectToAction("ReviewInfo", new {id = reviewId});
        }


        private void UpdateGamePopularValue(Game game)
        {
            int feedbackValue = game.Reviews.Sum(r => r.Feedbacks.Count);
            game.PopularGameValue = (int)((game.AverageRating * .33) + (game.Reviews.Count * .33) + (feedbackValue * .33));
        }
        private string GenerateID()
        {
            Random random = new Random();
            string ID = "";
            for (int i = 0; i < 16; i++)
            {
                int num = random.Next(48, 58);
                int upper = random.Next(65, 91);
                int lower = random.Next(97, 123);

                int which = random.Next(3);
                if (which == 0)
                {
                    ID = ID + (char)num;
                }
                else if (which == 1)
                {
                    ID = ID + (char)upper;
                }
                else if (which == 2)
                {
                    ID = ID + (char)lower;
                }
            }

            return ID;
        }
    }
}
